package taskmanager;

import java.io.File;
import java.io.Serializable;
import java.util.Date;

/**
 * Класс для описания задачи
 * Основными параметрами задачи являются:
 *  1. id пользователя
 *  2. id задачи
 *  3. список связанных с задачей файлов
 *  4. состояние выполнения задачи
 * Дополнительные параметры:
 *  5. время поступления задачи
 *  6. время выполнения задачи
 *  7. время последнего запуска задачи
 * Задача может находится в четырех состаяниях:
 *  1. Выполнение = ACTIVE - задача выполняется в данный момент
 *  2. Ожидание = WAITED - задача еще не выполнялась
 *  3. Остановка = STOPED - задача выполнялась, но была приостановлена
 *  4. Компилирование = COMPILING - задача еще не скомпилирована
 * При создании объекта класса автоматически устанавливаются:
 *  a. состояние выполнения задачи = ожидание (Waited)
 *  b. id задачи = id посленей задачи + 1
 *  с. время поступления задачи = текущее время системы
 * @author Volk, Alex-Rude
 */
public class JTask implements Comparable<JTask>, Serializable {
    /** счетчик задач. равен id последней задачи + 1 */
    private volatile static long taskIDCounter = 0;

    /** признак выполнения - задача выполняется в данный момент */
    public static final int ACTIVE = 3;
    /** признак ожидания - задача еще не выполнялась */
    public static final int STOPED = 2;
    /** признак остановки - задача выполнялась, но была приостановлена */
    public static final int WAITED = 1;
    /** признак компилирования - задача еще не откомпилированна */
    public static final int COMPILING = 0;
    /** признак блокировки - задача неактивна пока не будет разблокирована */
    public static final int BLOCKED = -1;
    /** признак нераспределенности - задача не прикреплена к серверу */
    public static final int STRAYED = -2;
    /** признак ошибки - неудачный запуск */
    public static final int ERROR = -3;
    /** признак завершения - задача завершена */
    public static final int ENDED = -4;
    /** признак неопознанного состояния - состояние неизвестно */
    public static final int UNKNOWN = -5;

    /** идентификатор пользователя */
    private long userID = -1;
    /** идентификатор задачи */
    private long taskID = -1;

    /** число процессов, выделяемых задаче */
    private int procNum=0;
    /** файл для компиляции */
    private String sourcePath = null;
    /** log компиляции */
    private String logSourcePath = null;
    /** исполняемый файл */
    private String execPath = null;
    /** log исполняемого файла */
    private String logExecPath = null;
    /** список файлов, связанных с задачей */
    private String attachedPaths[] = null;
    /** состояние выполнения задачи */
    private int status;
    /** время вхождения в систему */
    private Date enterTime;
    /** время последнего запуска */
    private Date lastRunTime;
    /** суммарное время выполнения задачи (миллисекунды) */
    private long timeInRun=0;
    /** признак откомпилированной задачи */
    private boolean isCompil=false;

    /**
     * Установить счетчик задач
     * @param counter значение счетчика. не должно равняться id существующей задачи
     */
    static void setTaskIDCounter(long counter){taskIDCounter=counter;}
    /**
     * Запросить счетчик заач
     * @return значение счетчика
     */
    static long getTaskIDCounter(){return taskIDCounter;}

    /**
     * Создать задачу
     * @param userID id пользователя
     * @param isCompil true - задача откомпилирована, false - не откомпиирована
     * @param startFile основной файл исходников или исполняемый файл
     * @param attachedFiles список прилагаемых к задаче файлов
     * @param procNum число процессов для задачи
     */
    public JTask(long userID, boolean isCompil,
            String sourcePath,String execPath, String attachedPaths[],int procNum){
        if( (sourcePath==null && !isCompil) || execPath==null )
            throw new NullPointerException();
        this.userID = userID;
        this.attachedPaths = attachedPaths;
        this.sourcePath=sourcePath;
        this.execPath=execPath;
        this.procNum=procNum;
        //определить log файлы
        if(sourcePath!=null) logSourcePath=sourcePath+".clog";
        if(execPath!=null)   logExecPath=execPath+".elog";
        //if(isCompil) status = COMPILING; //необходима компиляция
        //else status = WAITED; //установить статус в ожидание
        this.isCompil=isCompil;
        status = WAITED; //установить статус в ожидание
        taskID = taskIDCounter++; //установить id задачи от счетчика
        enterTime=new Date(); //засечь время вхождения
    }

    /**
     * Конструктор копирования
     * @param task задача
     */
    public JTask(JTask task){
        if(task==null) throw new NullPointerException();
        userID=task.getUserID();
        attachedPaths=task.getAttachedFiles();
        sourcePath=task.getSourceFile();
        execPath=task.getExecFile();
        logSourcePath=task.getLogSourceFile();
        logExecPath=task.getLogExecFile();
        isCompil=task.isCompiled();
        status=task.getStatus();
        taskID=task.getTaskID();
        enterTime=task.getEnterTime();
        lastRunTime=task.getLastRunTime();
        procNum=task.getProcNum();
    }

    /**
     * установить статус выполнения задачи
     * @param status статус выполнения
     * @return true - статус изменен, false - неизвестный статус
     */
    public boolean setStatus(int status){
        switch(status){
            case WAITED:
            case COMPILING:
                timeInRun=0; //сброс времени выполнения
                break;
            case ACTIVE:
                //запомнить время посленего запуска
                if(this.status!=ACTIVE) lastRunTime=new Date();
                break;
            case BLOCKED:
            case STOPED:
            case STRAYED:
            case ERROR:
            case ENDED:
            case UNKNOWN:
                //если задача была активна - вычислить сколько она выполнялась
                if(status==ACTIVE){
                    Date tmpDate = new Date();
                    timeInRun+=tmpDate.getTime()-lastRunTime.getTime();
                }
                break;
            default:
                return false;
        }
        //изменить статус
        this.status=status;
        return true;
    }

//    /** Установить признак приостановки задачи */
//    void setStop(){
//        //если задача была активна - вычислить сколько она выполнялась
//        if(status==ACTIVE){
//            Date tmpDate = new Date();
//            timeInRun+=tmpDate.getTime()-lastRunTime.getTime();
//        }
//        status = STOPED;
//    }
//    /** Установить признак выполнения задачи */
//    void setActive(){
//        if(status!=ACTIVE) lastRunTime=new Date();
//        status = ACTIVE;
//    }
//    /** Установить признак ожидания задачи */
//    void setWait(){
//        timeInRun=0; //сброс времени выполнения
//        status = WAITED;
//    }
//    /** Установить признак блокировки */
//    void setBlock(){
//        //если задача была активна - вычислить сколько она выполнялась
//        if(status==ACTIVE){
//            Date tmpDate = new Date();
//            timeInRun+=tmpDate.getTime()-lastRunTime.getTime();
//        }
//        status = BLOCKED;
//    }
//    /** Установить признак нераспределенности */
//    void setStrayed(){
//        //если задача была активна - вычислить сколько она выполнялась
//        if(status==ACTIVE){
//            Date tmpDate = new Date();
//            timeInRun+=tmpDate.getTime()-lastRunTime.getTime();
//        }
//        status = STRAYED;
//    }
//    /** Установить признак неопрееенности */
//    void setUnknown(){
//        //если задача была активна - вычислить сколько она выполнялась
//        if(status==ACTIVE){
//            Date tmpDate = new Date();
//            timeInRun+=tmpDate.getTime()-lastRunTime.getTime();
//        }
//        status = UNKNOWN;
//    }
    /**
     * Запросить идентификатор пользователя
     * @return идентификатор пользователя
     */
    public long getUserID(){return userID;}
    /**
     * Запросить состояние выполнения задачи
     * @return состояние выполнения задачи
     */
    public int getStatus(){return status;}
    /**
     * Запросить ID задачи
     * @returnID задачи
     */
    public long getTaskID(){return taskID;}
    /**
     * Запросить основной файл исходников
     * @return основной файл
     */
    public String getSourceFile(){return sourcePath;}
    /**
     * Запросить лог компиляции
     * @return лог файл
     */
    public String getLogSourceFile(){return logSourcePath;}
    /**
     * Запросить исполняемый файл
     * @return исполняемый файл
     */
    public String getExecFile(){return execPath;}
    /**
     * Запросить лог исполнения
     * @return лог файл
     */
    public String getLogExecFile(){return logExecPath;}
    /**
     * Запросить файлы, связанные с задачей
     * @return массив файлов, связанных с задачей
     */
    public String[] getAttachedFiles(){return attachedPaths;}
    /**
     * Запросить число процессов для задачи
     * @return число процессов для задачи
     */
    public int getProcNum(){ return procNum;}
    /**
     * Запросить время вхождения задачи в систему
     * @return время вхождения задачи в систему
     */
    public Date getEnterTime(){return enterTime;}
    /**
     * Запросить время последнего запуска задачи
     * @return время последнего запуска задачи
     */
    public Date getLastRunTime(){return lastRunTime;}
    /**
     * Запросить время выполнения задачи
     * @return время выполнения задачи (в миллисекундах)
     */
    public long getTimeInRun(){
        //если задача в данный момент активна - учесть текущий запуск
        if(status==ACTIVE){
            Date tmpDate = new Date();
            return timeInRun + ( tmpDate.getTime()-lastRunTime.getTime() );
        }
        else return timeInRun;
    }
    /**
     * Сравнить приоритеты задач
     * Сравниваются состояния выполнения текущей задачи и передаваемой
     * Приоритеты: Активная > Остановленная > Ожидающая
     * @param o задача с которой необходимо сравнить приоритет
     * @return 0 - приоритеты равны
     *      -1 - приоритет передаваемой задачи выше
     *      1  - приоритет передаваемой задачи ниже
     */
    @Override
    public int compareTo(JTask o) {
        if(status == getStatus()) return 0;
        if(status < o.getStatus()) return -1;
        return 1;
    }
    /**
     * Получить хэш код задачи. В качестве хэш кода используется id задачи
     * @return хэщ код
     */
    @Override
    public int hashCode(){ return (int)taskID;}
    
    /**
     * Установить статус компиляции
     * @param flag true - задача откомпилирована, false - не откомпилирована
     */
    void setCompiled(boolean flag){isCompil=flag;}
    
    /**
     * Проверить откомпилированность задачи
     * @return true - задача откомпилирована, false - не откомпилирована
     */
    public boolean isCompiled(){return isCompil;}

    /**
     * Проверить возможность активации задачи
     * @return true - задача может быть активирована, false - нельзя активировать
     */
    public boolean mayActivate(){
        if(status<0) return false; // состояния BLOCKED и UNKNOWN недопустимы
        return true;
    }
}
